package main

import "fmt"

/*
range 关键字用于 for 循环中迭代数组(array)、切片(slice)、通道(channel)或集合(map)的元素。
在数组和切片中它返回元素的索引和索引对应的值，在集合中返回 key-value 对的 key 值。
*/
func main() {
	//求和，不需要索引所以第一个用下划线
	nums := []int{1, 2, 3}
	sum := 0
	for _, num := range nums {
		sum += num
	}
	fmt.Println("sum:", sum)

	//需要索引
	for i, num := range nums {
		if num == 3 {
			fmt.Println("index:", i)
		}
	}

	//用在map上
	kvs := map[string]string{"a": "apple", "b": "banana"}
	for k, v := range kvs {
		fmt.Printf("%s - %s\n", k, v)
	}
	for k := range kvs {
		fmt.Println("key", k)
	}

	//range也可以用来枚举Unicode字符串。第一个参数是字符的索引，第二个是字符（Unicode的值）本身。
	for i, c := range "go" {
		fmt.Println(i, c)
	}

	//注意,range 会复制对象
	a := [3]int{0, 1, 2}
	for i, v := range a { // index、value 都是从复制品中取出
		if i == 0 {
			a[1], a[2] = 999, 999 // 在修改前,我们先修改原数组
			fmt.Println(a)        // 确认修改有效,输出 [0, 999, 999]
		}
		a[i] = v + 100 // 使用用复制品中取出的 value 修改原数组

	}
	fmt.Println(a) // 输出 [100, 101, 102]

	//建议改用用引用用类型,其底层数据不会被复制
	s := []int{1, 2, 3, 4, 5}
	for i, v := range s { // 复制 struct slice { pointer, len, cap }
		if i == 0 {
			s = s[:3]  // 对 slice 的修改,不会影响 range
			s[2] = 100 // 对底层数据的修改
		}
		fmt.Println(i, v)
	}
	fmt.Println(s)
}
